#include <stdio.h>
#include <string.h>
#include "des.h"

void print_bits(const bool* in, int bytes) {
    for (int i = 0; i < bytes; ++i) {
        for (int j = 0; j < 8; ++j) {
            printf("%c", in[i * 8 + j] ? '1' : '0');
        }
        printf(" ");
    }
    printf("\n");
}

void print_bytes(const char* in, int bytes) {
    for (int i = 0; i < bytes; ++i) {
        printf("0x%02x ",(unsigned char)in[i]);
    }
    printf("\n");
}

int main(int argc, char const *argv[]) {
    // 设置密钥
    char key[8] = "00000000";
    printf("密钥：");
    print_bytes(key, 8);
    // 生成子密钥
    struct SUBKEY skey;
    Set_SubKey(&skey, key);
    // 发送消息
    char m[8] = "11111111";
    printf("原文：");
    print_bytes(m, 8);
    // 分组加密
    char c[sizeof(m)];
    DES(c, m, &skey, true);
    printf("密文：");
    print_bytes(c, 8);
    // 分组加密的解密
    char d[sizeof(c)];
    DES(d, c, &skey, false);
    printf("译文：");
    print_bytes(d, 8);
    return 0;
}

static void DES(char out[8], char in[8], const SUBKEY_P pskey, bool type) {
    bool _in[64];
    ByteToBit(_in, in, 64);
    // 初始变换
    static const char IP_Table[64] = {    
        57, 49, 41, 33, 25, 17, 9 , 1,
        59, 51, 43, 35, 27, 19, 11, 3,
        61, 53, 45, 37, 29, 21, 13, 5,
        63, 55, 47, 39, 31, 23, 15, 7,
        56, 48, 40, 32, 24, 16, 8 , 0,
        58, 50, 42, 34, 26, 18, 10, 2,
        60, 52, 44, 36, 28, 20, 12, 4,
        62, 54, 46, 38, 30, 22, 14, 6,
    };
    bool data[17][64];
    TRANSFORM(data[0], _in, IP_Table, 64);
    // Feistel网络的16轮变换
    for (int i = 0; i < 16; ++i) {
        // L[i+1] = R[i]
        memcpy(data[i+1], data[i] + 32, 32);
        // R[i+1] = L[i] ^ F(R[i])
        F_FUNCTION(data[i+1] + 32, data[i] + 32, pskey->key[type ? i : 15 - i]);
        XOR(data[i+1] + 32, data[i], 32);
    }
    CYCLELEFT(data[16], 64, 32);
    // 初始变换的逆变换
    static const char IP_inv_Table[64] = {
        39, 7 , 47, 15, 55, 23, 63, 31, 
        38, 6 , 46, 14, 54, 22, 62, 30,
        37, 5 , 45, 13, 53, 21, 61, 29,
        36, 4 , 44, 12, 52, 20, 60, 28,
        35, 3 , 43, 11, 51, 19, 59, 27,
        34, 2 , 42, 10, 50, 18, 58, 26,
        33, 1 , 41, 9 , 49, 17, 57, 25,
        32, 0 , 40, 8 , 48, 16, 56, 24,
    };
    bool _out[64];
    TRANSFORM(_out, data[16], IP_inv_Table, 64);
    BitToByte(out, _out, 64);
}

static void Set_SubKey(SUBKEY_P pskey, const char key[8]) {
    bool _key[64];
    ByteToBit(_key, key, 64);
    // 置换选择1
    static const char PC_1[56] = {
        56, 48, 40, 32, 24, 16, 8 ,   
        0 , 57, 49, 41, 33, 25, 17,   
        9 , 1 , 58, 50, 42, 34, 26,   
        18, 10, 2 , 59, 51, 43, 35,   
        62, 54, 46, 38, 30, 22, 14,   
        6 , 61, 53, 45, 37, 29, 21,   
        13, 5 , 60, 52, 44, 36, 28,   
        20, 12, 4 , 27, 19, 11, 3 ,
    };
    bool tmp[56];
    TRANSFORM(tmp, _key, PC_1, 56);
    // 16轮迭代，变换出16个子密钥
    for (int i = 0; i < 16; ++i) {
        // 对左移位的规定
        static const int move_times[16] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
        CYCLELEFT(tmp, 28, move_times[i]);
        CYCLELEFT(tmp + 28, 28, move_times[i]);
        // 置换选择2   
        static const char PC_2[48] = {
            13, 16, 10, 23, 0 , 4 , 2 , 27,   
            14, 5 , 20, 9 , 22, 18, 11, 3 ,   
            25, 7 , 15, 6 , 26, 19, 12, 1 ,   
            40, 51, 30, 36, 46, 54, 29, 39,   
            50, 44, 32, 46, 43, 48, 38, 55,   
            33, 52, 45, 41, 49, 35, 28, 31,
        };
        TRANSFORM(pskey->key[i], tmp, PC_2, 48);
    }
}

static void F_FUNCTION(bool out[32], const bool in[32], const bool ki[48]) {
    // 扩展
    static const char E_Table[48] = {
        31, 0, 1, 2, 3, 4,  
        3 , 4, 5, 6, 7, 8,  
        7 , 8, 9,10,11,12,  
        11,12,13,14,15,16,  
        15,16,17,18,19,20,  
        19,20,21,22,23,24,  
        23,24,25,26,27,28,  
        27,28,29,30,31, 0,
    };  
    bool a[48];
    TRANSFORM(a, in, E_Table, 48);
    // 异或
    XOR(a, ki, 48);
    // 代替
    bool b[32];
    S_BOXF(b, a);
    // 置换
    static const char P_Table[32] = {
        15,6 ,19,20,28,11,27,16,  
        0 ,14,22,25,4 ,17,30,9 ,  
        1 ,7 ,23,13,31,26,2 ,8 ,  
        18,12,29,5 ,21,10,3 ,24,
    };  
    TRANSFORM(out, b, P_Table, 32);
}

static void S_BOXF(bool out[32], const bool in[48]) {
    // 8个S盒
    static const char S_Boxs[8][4][16] = {
        {
            {14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},  
            {0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8},  
            {4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0},  
            {15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13},
        },  
        {
            {15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10},  
            {3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5},  
            {0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15},  
            {13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9},
        },
        {
            {10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8},  
            {13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1},  
            {13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7},  
            {1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12},
        },   
        {
            {7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15},  
            {13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9},  
            {10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4},  
            {3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14},
        },   
        {
            {2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9},  
            {14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6},  
            {4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14},  
            {11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3},
        },  
        {
            {12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11},  
            {10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8},  
            {9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6},  
            {4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13},
        },  
        {
            {4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1},  
            {13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6},  
            {1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2},  
            {6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12},
        },
        {
            {13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7},  
            {1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2},  
            {7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8},  
            {2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11},
        },
    };
    for (int i = 0; i < 8; ++i) {
        // 6位的输入
        const bool *p = in + 6 * i;
        int r = p[0] * 2 + p[5];
        int c = p[1] * 8 + p[2] * 4 + p[3] * 2 + p[4];
        char half_byte = S_Boxs[i][r][c];
        // 4位的输出
        bool *q = out + 4 * i;
        q[0] = (half_byte & 8) >> 3;
        q[1] = (half_byte & 4) >> 2;
        q[2] = (half_byte & 2) >> 1;
        q[3] = (half_byte & 1) >> 0;
    }
}

static void TRANSFORM(bool *out, const bool *in, const char *table, int len) {
    for (int i = 0; i < len; ++i) {
        out[i] = in[table[i]];
    }
}

static void XOR(bool *inA, const bool *inB, int len) {
    for (int i = 0; i < len; ++i) {
        inA[i] ^= inB[i];
    }
}

static void CYCLELEFT(bool *in, int len, int loop) {
    bool tmp[len];
    memcpy(tmp, in, len);
    memcpy(in, tmp + loop, len - loop);
    memcpy(in + len - loop, tmp, loop);
}

static void ByteToBit(bool *out, const char *in, int bits) {
    int bytes = bits / 8;
    for (int i = 0; i < bytes; ++i) {
        for (int j = 0; j < 8; ++j) {
            out[i * 8 + j] = (in[i] >> (7-j)) & 1;
        }
    }
}

static void BitToByte(char *out, const bool *in, int bits) {
    int bytes = bits / 8;
    for (int i = 0; i < bytes; ++i) {
        for (int j = 0; j < 8; ++j) {
            out[i] = (out[i] << 1) | in[i * 8 + j];
        }
    }
}
